package de.popforge.ui
{
	import flash.display.GradientType;
	import flash.display.Graphics;
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.filters.DropShadowFilter;
	import flash.geom.Matrix;
	
	/**
		class Slider
		
		every parameter is clamp in range [0,1]
		which makes it much easier to control them independently
	**/
	
	public class Slider extends Sprite
	{
		//-- events
		public var onChanged: Function;

		private var barSize: int;
		private var barStrength: int;
		private var align: String;
		
		private var spriteKnob: Sprite;
		
		private var spriteFrame: Sprite;
		private var upBTN: Sprite;
		private var downBTN: Sprite;
		
		private var m: Matrix;
		
		private var knobSize: int;
		private var dragOffset: int;
		
		private var value: Number = 0;
		
		public function Slider( _barSize:int, _barStrength:int, _align:String )
		{
			this.barSize = _barSize;
			this.barStrength = _barStrength;
			this.align = _align;
			
			m = new Matrix();
			
			createKnob();
			setKnobSize( 0 );
			addEventListener( MouseEvent.MOUSE_DOWN, onMDown );
			
			cacheAsBitmap = true;
		}
		
		public function setKnobSize( size: Number ): void
		{
			if( size < 1 )
			{
				knobSize = barSize * size;
				
				if( knobSize < barStrength )
					knobSize = barStrength;
				
				redrawKnob();
			}
			else
			{
				value = 0;
				removeKnob();
			}
			
			setKnobPosition( value * ( barSize - knobSize ) );
			
			if( onChanged != null )
				onChanged( this );
		}
		
		public function getKnobSize(): Number
		{
			return knobSize / barSize;
		}
		
		public function setValue( value: Number ): void
		{
			setKnobPosition( value * ( barSize - knobSize ) );
			
			this.value = value;
			
			if( onChanged != null )
				onChanged( this );
		}
		
		public function getValue(): Number
		{
			return value;
		}
		
		public function setBarSize( _barSize: Number ): void
		{
			this.barSize = _barSize;
//			setKnobSize( size );
		}
		
		protected function createKnob(): void
		{
			spriteKnob = new Sprite();
			spriteKnob.filters =
			[
				new DropShadowFilter( 0, 0, 0xff, 1, 8, 8, 1, 3, true ),
				new DropShadowFilter( 0, 0, 0, 1, 4, 4, 1, 3, true ),
			];
			
			spriteKnob.cacheAsBitmap = true;
			
			addChild( spriteKnob );
		}
		
		protected function redrawKnob(): void
		{
			var g: Graphics = spriteKnob.graphics;
			
			//-- draw knob
			g.clear();
			
			switch( align )
			{
				case SliderAlign.HORIZONTAL:
					m.createGradientBox( barSize-2, barStrength-2, -Math.PI/2, 1, 1 );
					g.beginGradientFill( GradientType.LINEAR, [ 0x8FBBFF, 0x0046B2, 0xFFFFFF ], [ 1, 1, 1 ], [ 0, 160, 255 ], m );
					g.drawRoundRect( 1, 1, knobSize-1, barStrength-1, barStrength-1, barStrength-1 );
					break;
					
				case SliderAlign.VERTICAL:
					m.createGradientBox( barStrength-2, barSize-2, Math.PI, 1, 1 );
					g.beginGradientFill( GradientType.LINEAR, [ 0x8FBBFF, 0x0046B2, 0xFFFFFF ], [ 1, 1, 1 ], [ 0, 160, 255 ], m );
					g.drawRoundRect( 1, 1, barStrength-1, knobSize-1, barStrength-1, barStrength-1 );
					break;
			}

			g.endFill();
		}
		
		protected function removeKnob(): void
		{
			spriteKnob.graphics.clear();
		}
		
		protected function setKnobPosition( pos: int ): void
		{
			switch( align )
			{
				case SliderAlign.HORIZONTAL:
					spriteKnob.x = pos; break;
				case SliderAlign.VERTICAL:
					spriteKnob.y = pos; break;
			}
		}
		
		private function move(): void
		{
			var pos: int = ( align == SliderAlign.HORIZONTAL ? mouseX : mouseY ) - dragOffset;
			
			//-- constrain position to bar
			if( pos < 0 )
				pos = 0;
			else
			if( pos > barSize - knobSize )
				pos = barSize - knobSize;
			
			//-- apply position
			setKnobPosition( pos );
			
			//-- compute unified value [0,1]
			var newValue: Number = pos / ( barSize - knobSize );
			
			if( newValue != value )
			{
				value = newValue;
				
				//-- throw event
				if( onChanged != null )
					onChanged( this );
			}
		}
		
		/*
		 * START DRAGGING
		 */
		
		private function onMDown( event: MouseEvent ): void
		{
			//-- init MouseEvents
			stage.addEventListener( MouseEvent.MOUSE_MOVE, onMMove );
			stage.addEventListener( MouseEvent.MOUSE_UP, onMUp );
			
			//-- get cursor offset
			if( event.target == spriteKnob )
				dragOffset = align == SliderAlign.HORIZONTAL ? spriteKnob.mouseX : spriteKnob.mouseY;
			else
				dragOffset = knobSize >> 1;
			
			//-- move immediately
			move();
		}
		
		private function onMMove( event: MouseEvent ): void
		{
			move();
		}
		
		private function onMUp( event: MouseEvent ): void
		{
			//-- stop listening
			stage.removeEventListener( MouseEvent.MOUSE_MOVE, onMMove );
			stage.removeEventListener( MouseEvent.MOUSE_UP, onMUp );
			
			//-- ensure moving to last mouse position
			move();
		}
	}
}